package tkaczyk.simtalk.message;

import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.apache.log4j.Logger;

public class MessageParser implements Iterator<Message>, Iterable<Message> {
	private String xmlString;
	private XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
	private XMLEventReader xmlEventReader;

	private boolean readyNextMessage = false;
	private boolean readyToParse = false;
	private Message currentMessage;

	private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private static final QName SEQ_NO = new QName("seqNo");

	private static Logger log = Logger.getRootLogger();

	public MessageParser() {
	}

	public void parseXML(String nextXMLChunk) {
		xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<wrapper>\n" + nextXMLChunk + "</wrapper>\n";
		readyToParse = true;
		try {
			xmlEventReader = xmlInputFactory.createXMLEventReader(new StringReader(xmlString));
		} catch (XMLStreamException e) {
			log.error(e);
		}
	}

	@Override
	public Iterator<Message> iterator() {
		return this;
	}

	@Override
	public boolean hasNext() {
		if (currentMessage != null) {
			return true;
		} else if (!readyToParse || xmlEventReader == null) {
			return false;
		} else {
			Message nextMessage = new Message();
			readyNextMessage = false;
			try {
				while (!readyNextMessage) {
					XMLEvent event;
					if (xmlEventReader.hasNext()) {
						event = xmlEventReader.nextEvent();
					} else {
						readyToParse = false;
						break;
					}
					switch (event.getEventType()) {
					case XMLEvent.START_ELEMENT:
						StartElement startElem = event.asStartElement();
						String elem = startElem.getName().toString();
						if (elem == "message") {
							nextMessage.seqNo = Integer.parseInt(startElem.getAttributeByName(SEQ_NO).getValue().toString());
						} else if (elem == "nick") {
							nextMessage.nick = xmlEventReader.getElementText();
						} else if (elem == "sent") { 
							nextMessage.sent = dateFormat.parse(xmlEventReader.getElementText());
						} else if (elem == "body") {
							nextMessage.body = xmlEventReader.getElementText();
						}
						break;
					case XMLEvent.END_ELEMENT:
						if (event.asEndElement().getName().toString().equals("message")) {
							nextMessage.target = Message.Target.INCOMING;
							nextMessage.received = new Date();
							nextMessage.xml = MessagePreparer.createXMLString(nextMessage);
							readyNextMessage = true;
						}
					}
				}
				if (readyNextMessage) {
					currentMessage = nextMessage;
					return true;
				} else {
					currentMessage = null;
					readyToParse = false;
					return false;
				}
			} catch (ParseException e) {
				log.error(e);
				readyToParse = false;
				return false;
			} catch (XMLStreamException e) {
				log.error(e);
				readyToParse = false;
				return false;
			}
		}
	}

	@Override
	public Message next() {
		if (hasNext()) {
			Message ret = currentMessage;
			currentMessage = null;
			return ret;
		} else {
			throw new NoSuchElementException();
		}
	}

	@Override
	public void remove() {
	}
}
